/**
 * Copyright (c) 2010 CWI Amsterdam and others. All rights reserved.
 * This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     CWI Amsterdam - initial API and implementation
 */
package nl.cwi.arne.util;

import nl.cwi.arne.Node;
import nl.cwi.arne.NodeActivation;
import nl.cwi.arne.impl.NodeActivationImpl;

/**
 * An iterator for node activation maps.
 * @author Christian Krause
 * @generated NOT
 */
public class NodeActivationIterator implements ArneIterator<NodeActivation> {
	
	// The node:
	private Node node;

	// The next activation:
	private NodeActivation next;

	// Number of incoming arcs:
	private int arcs;
	
	// Size of the data array:
	private int dataSize;
	
	// Highest possible activation level.
	private byte highest;
	
	// Maximum number of map that will be generated.
	private long maxCount;
	
	// Number of skipped activations.
	private long skipped;
	
	// Whether the node is monotonic.
	private boolean monotonic;
	
	/**
	 * Default constructor.
	 * @param node Node that we compute transition maps for.
	 */
	public NodeActivationIterator(Node node) {
		this.node = node;
		reset();
	}
	
	/**
	 * Reset this iterator.
	 */
	public void reset() {

		// Some meta-data:
		highest = (byte) (node.getLevels()-1);
		arcs = node.getIncoming().size();
		maxCount = (long) Math.pow(node.getLevels(),1 << node.getIncoming().size());
		dataSize = NodeActivationIndexConverter.getIndexCount(arcs);
		monotonic = node.isMonotonic();
		
		// Generate the first activation:
		next = new NodeActivationImpl(node);
		while (next!=null && !nextIsValid()) next();
		
	}
	
	/*
	 * (non-Javadoc)
	 * @see java.util.Iterator#hasNext()
	 */
	public boolean hasNext() {
		return next!=null;
	}
	
	/*
	 * (non-Javadoc)
	 * @see java.util.Iterator#next()
	 */
	public NodeActivation next() {
		
		NodeActivation result = next;
		if (result!=null) {
			
			// Copy the current map:
			next = (NodeActivation) result.getCopy();
			byte[] data = next.getData();
			
			// Reset number of skipped activations:
			skipped = -1;
			
			do {
				// Increase the number of skipped activations:
				skipped++;
				
				// Increase the data array:
				boolean last = true;
				
				for (int i=0; i<dataSize; i++) {
					if (data[i]==highest) {
						data[i] = 0;
					} else {
						data[i] = (byte) (data[i] + 1);
						last = false;
						break;
					}
				}
				// If it was already the last one we stop.
				if (last) {
					next = null;
				}
			} while (next!=null && !nextIsValid());
			
		}
		return result;
		
	}
	
	/*
	 * Check is the next activation map is valid.
	 */
	private boolean nextIsValid() {
		return (!monotonic || next.isMonotonic());
	}
	
	/*
	 * (non-Javadoc)
	 * @see java.util.Iterator#remove()
	 */
	public void remove() {
		throw new UnsupportedOperationException();
	}
	
	/*
	 * (non-Javadoc)
	 * @see nl.cwi.arne.util.ArneIterator#getMaxCount()
	 */
	public long getMaxCount() {
		return maxCount;
	}
	
	/*
	 * (non-Javadoc)
	 * @see nl.cwi.arne.util.ArneIterator#getSkipped()
	 */
	public long getSkipped() {
		return skipped;
	}
		
}
